<?php

declare(strict_types=1);
/**
 * This file is part of MoChat.
 * @link     https://mo.chat
 * @document https://mochat.wiki
 * @contact  group@mo.chat
 * @license  https://github.com/mochat-cloud/mochat/blob/master/LICENSE
 */
namespace MoChat\App\WorkRoom\Logic;

use Hyperf\Di\Annotation\Inject;
use MoChat\App\Corp\Contract\CorpContract;
use MoChat\App\WorkContact\Contract\WorkContactRoomContract;
use MoChat\App\WorkDepartment\Contract\WorkDepartmentContract;
use MoChat\App\WorkEmployee\Contract\WorkEmployeeContract;
use MoChat\App\WorkEmployee\Contract\WorkEmployeeDepartmentContract;
use MoChat\App\WorkRoom\Constants\Status as WorkRoomStatus;
use MoChat\App\WorkRoom\Contract\WorkRoomContract;
use MoChat\App\WorkRoom\Contract\WorkRoomGroupContract;
use MoChat\Plugin\RoomTag\Contract\RoomTagContract;
use MoChat\Plugin\RoomTag\Contract\RoomTagPivotContract;

/**
 * 客户群管理-列表.
 *
 * Class IndexLogic
 */
class IndexLogic
{
    /**
     * @Inject
     * @var WorkRoomContract
     */
    protected $workRoomService;

    /**
     * @Inject
     * @var WorkEmployeeContract
     */
    protected $workEmployeeService;

    /**
     * @Inject
     * @var CorpContract
     */
    protected $corpService;

    /**
     * @Inject
     * @var WorkRoomGroupContract
     */
    protected $workRoomGroupService;

    /**
     * @Inject
     * @var WorkContactRoomContract
     */
    protected $workContactRoomService;

    /**
     * @Inject
     * @var RoomTagPivotContract
     */
    protected $roomTagPivotService;

    /**
     * @Inject
     * @var WorkEmployeeDepartmentContract
     */
    protected $workEmployeeDepartmentService;

    /**
     * @Inject
     * @var WorkDepartmentContract
     */
    protected $workDepartmentService;

    /**
     * @Inject
     * @var RoomTagContract
     */
    protected $roomTagService;

    /**
     * @var
     */
    protected $totalNum;

    /**
     * @var
     */
    protected $dayNum;

    /**
     * @var
     */
    protected $dayJoinNum;

    /**
     * @var
     */
    protected $dayOutNum;

    /**
     * @param array $user 登录用户信息
     * @param array $params 请求参数
     * @return array 响应数组
     */
    public function handle(array $user, array $params): array
    {
        // 根据群主、群名称、群状态、群标签查询客户群id
        $roomIds = $this->handleWhere($user, $params);
        if (empty($roomIds)) {
            return [
                'page' => [
                    'perPage' => $params['perPage'],
                    'total' => 0,
                    'totalPage' => 0,
                ],
                'list' => [],
            ];
        }
        $rooms = [];
        foreach ($roomIds as $roomId) {
            $rooms[] = ['total' => 0, 'roomId' => $roomId];
        }

        // 群内总人数
        $this->totalNum = $this->getTotalNum($roomIds);
        $day = empty($params['day']) ? date('Y-m-d') : $params['day'];
        $tomorrow = empty($params['day']) ? date('Y-m-d', strtotime('+1 day')) : date('Y-m-d', strtotime($params['day']) + 86400);
        // 当日群人数
        $this->dayNum = $this->getDayNum($roomIds, $tomorrow, 1, 1);
        // 当日入群人数
        $this->dayJoinNum = $this->getDayNum($roomIds, $day, 2, 1);

        // 当日退群人数
        $this->dayOutNum = $this->getDayNum($roomIds, $day, 0, 2);

        $list = [];
        if (isset($params['order']) && in_array($params['order'], ['totalNum', 'joinNum', 'outNum'])) {
            // 群内总人数排名
            if ($params['order'] === 'totalNum' && ! empty($this->totalNum)) {
                $totalNum = $this->arraySort($this->totalNum, 'total', $params['orderRule']);
                $list = array_slice($totalNum, ($params['page'] - 1) * $params['perPage'], $params['perPage']);
            }
            // 入群人数排名
            if ($params['order'] === 'joinNum') {
                if (! empty($this->dayJoinNum)) {
                    $dayJoin = array_column($this->dayJoinNum, null, 'roomId');
                    foreach ($rooms as $k => $v) {
                        ! empty($dayJoin[$v['roomId']]) && $rooms[$k]['total'] = $dayJoin[$v['roomId']]['total'];
                    }
                }
                $dayJoinNum = $this->arraySort($rooms, 'total', $params['orderRule']);
                $list = array_slice($dayJoinNum, ($params['page'] - 1) * $params['perPage'], $params['perPage']);
            }
            // 退群人数排名
            if ($params['order'] === 'outNum') {
                if (! empty($this->dayOutNum)) {
                    $dayOut = array_column($this->dayOutNum, null, 'roomId');
                    foreach ($rooms as $k => $v) {
                        ! empty($dayOut[$v['roomId']]) && $rooms[$k]['total'] = $dayOut[$v['roomId']]['total'];
                    }
                }
                $dayOutNum = $this->arraySort($rooms, 'total', $params['orderRule']);
                $list = array_slice($dayOutNum, ($params['page'] - 1) * $params['perPage'], $params['perPage']);
            }
        }

        return $this->handleData($roomIds, $params, $list);
    }

    protected function handleData(array $roomIds, array $params, array $list): array
    {
        // 组织响应数据
        $data = [
            'page' => [
                'perPage' => $params['perPage'],
                'total' => 0,
                'totalPage' => 0,
            ],
            'list' => [],
        ];
        if (empty($params['order']) || $params['order'] === 'createTime') {
            $where[] = ['id', 'IN', $roomIds];
            // 分页信息
            $order = empty($params['order']) ? 'create_time desc' : 'create_time' . ' ' . $params['orderRule'];
            $options = [
                'page' => $params['page'],
                'perPage' => $params['perPage'],
                'orderByRaw' => $order,
            ];
            // 分页查询数据表
            $rooms = $this->workRoomService->getWorkRoomList($where, ['*'], $options);
            if (empty($rooms['data'])) {
                return $data;
            }
            $data['list'] = $this->getRooms($rooms['data']);
            $data['page']['total'] = $rooms['total'];
            $data['page']['totalPage'] = $rooms['last_page'];
        } elseif (! empty($list)) {
            $orderRoomIds = array_column($list, 'roomId');
            $rooms = $this->workRoomService->getWorkRoomsById($orderRoomIds);
            $list = $this->getRooms($rooms);
            $data['list'] = $this->order($params, $list);
            $total = $this->getTotal($params, $roomIds);
            $data['page']['total'] = $total['total'] ?? 0;
            $data['page']['totalPage'] = $total['totalPage'] ?? 0;
        }
        return $data;
    }

    /**
     * 排序.
     */
    protected function order(array $params, array $list): array
    {
        if (isset($params['order']) && in_array($params['order'], ['totalNum', 'joinNum', 'outNum'])) {
            if ($params['order'] === 'totalNum') {
                return $this->arraySort($list, 'totalNum', $params['orderRule']);
            }
            if ($params['order'] === 'joinNum') {
                return $this->arraySort($list, 'dayJoinNum', $params['orderRule']);
            }
            if ($params['order'] === 'outNum') {
                return $this->arraySort($list, 'dayOutNum', $params['orderRule']);
            }
        }
        return $list;
    }

    protected function getTotal(array $params, array $roomIds): array
    {
        $total = ['total' => 0, 'totalPage' => 0];
        if ($params['order'] === 'totalNum' && ! empty($this->totalNum)) {
            $total['total'] = count($this->totalNum);
            $total['totalPage'] = ceil($total['total'] / $params['perPage']);
        }
        if ($params['order'] === 'outNum' || $params['order'] === 'joinNum') {
            $total['total'] = count($roomIds);
            $total['totalPage'] = ceil($total['total'] / $params['perPage']);
        }
        return $total;
    }

    protected function getTotalNum(array $roomIds): array
    {
        return $this->workContactRoomService->countWorkContactRoomsByRoomIds($roomIds, 1);
    }

    protected function getDayNum(array $roomIds, string $day, int $type, int $status): array
    {
        return $this->workContactRoomService->countWorkContactRoomsByRoomIdsDay($roomIds, $day, $type, $status);
    }

    /**
     * 处理列表查询条件.
     */
    protected function handleWhere(array $user, array $params): array
    {
        // 群主、群名称、群状态
        $params['corpId'] = $user['corpIds'][0];
        $rooms = $this->workRoomService->getWorkRoomsBySearch($params, ['id']);
        if (empty($rooms)) {
            return [];
        }
        $roomIds = array_column($rooms, 'id');
        // 群标签
        if (! empty($params['tags'])) {
            $roomTagPivot = $this->roomTagPivotService->getRoomTagPivotByRoomIdsTagIds($roomIds, $params['tags']);
            if (empty($roomTagPivot)) {
                return [];
            }
            $roomIds = array_unique(array_column($roomTagPivot, 'roomId'));
        }
        return $roomIds;
    }

    /**
     * @param array $rooms 请求参数
     * @return array 响应数组
     */
    private function getRooms(array $rooms): array
    {
        // 群主信息-群主名称-所属公司名称
        $ownerIdArr = array_unique(array_column($rooms, 'ownerId'));

        $ownerList = $this->workEmployeeService->getWorkEmployeesById($ownerIdArr, ['id', 'corp_id', 'name']);

        empty($ownerList) || $ownerList = array_column($ownerList, null, 'id');
        // 查询客服所属部门
        $department = $this->getEmployeeDepartment($ownerIdArr);
        // 群标签
        $roomIds = array_unique(array_column($rooms, 'id'));
        $roomTags = $this->getRoomTags($roomIds);
        // 群人数
        $totalNum = empty($this->totalNum) ? [] : array_column($this->totalNum, null, 'roomId');
        // 当日群人数
        $dayNum = empty($this->dayNum) ? [] : array_column($this->dayNum, null, 'roomId');
        // 当日入群
        $dayJoinNum = empty($this->dayJoinNum) ? [] : array_column($this->dayJoinNum, null, 'roomId');
        // 当日退群
        $dayOutNum = empty($this->dayOutNum) ? [] : array_column($this->dayOutNum, null, 'roomId');
        // 处理列表数据
        $list = [];
        foreach ($rooms as $room) {
            // 群主信息
            $owner = $ownerList[$room['ownerId']] ?? [];
            $ownerName = $owner['name'] ?? '';
            $list[] = [
                'id' => $room['id'],
                'ownerId' => $room['ownerId'],
                'wxChatId' => $room['wxChatId'],
                'roomName' => $room['name'],
                'ownerName' => $ownerName,
                'departmentName' => empty($department[$room['ownerId']]) ? [] : array_unique($department[$room['ownerId']]),
                'roomTag' => $roomTags[$room['id']] ?? [],
                'totalNum' => isset($totalNum[$room['id']]) ? $totalNum[$room['id']]['total'] : 0,
                'dayNum' => isset($dayNum[$room['id']]) ? $dayNum[$room['id']]['total'] : 0,
                'dayJoinNum' => isset($dayJoinNum[$room['id']]) ? $dayJoinNum[$room['id']]['total'] : 0,
                'dayOutNum' => isset($dayOutNum[$room['id']]) ? $dayOutNum[$room['id']]['total'] : 0,
                'status' => $room['status'],
                'statusText' => WorkRoomStatus::getMessage($room['status']),
                'createTime' => $room['createTime'],
            ];
        }

        return $list;
    }

    private function getRoomTags(array $roomIds): array
    {
        // 客户群标签
        $roomTags = $this->roomTagService->getRoomTagsByCorpId(user()['corpIds']);
        if (empty($roomTags)) {
            return [];
        }
        $roomTags = array_column($roomTags, null, 'id');
        $roomTagPivots = $this->roomTagPivotService->getRoomTagPivotByRoomIds($roomIds, ['room_id', 'room_tag_id']);
        $roomTag = [];
        foreach ($roomTagPivots as $item) {
            $roomTag[$item['roomId']][] = isset($roomTags[$item['roomTagId']]) ? $roomTags[$item['roomTagId']]['name'] : '';
        }
        return $roomTag;
    }

    private function getEmployeeDepartment($employeeIds): array
    {
        // 客服部门
        $department = $this->workEmployeeDepartmentService->getWorkEmployeeDepartmentsByEmployeeIds($employeeIds, ['employee_id', 'department_id']);
        if (empty($department)) {
            return [];
        }
        $departmentIds = array_column($department, 'departmentId');
        // 部门信息
        $departmentNames = $this->workDepartmentService->getWorkDepartmentsById($departmentIds, ['id', 'name']);
        if (empty($departmentNames)) {
            return [];
        }
        $departmentName = [];
        foreach ($departmentNames as $name) {
            $departmentName[$name['id']] = $name['name'];
        }
        // 客服部门名称
        $employeeDepartment = [];
        foreach ($department as $item) {
            $employeeDepartment[$item['employeeId']][] = $departmentName[$item['departmentId']];
        }
        return $employeeDepartment;
    }

    /**
     * 二维数组排列.
     * @param $array
     * @param $keys
     */
    private function arraySort($array, $keys, string $sort = 'asc'): array
    {
        $newArr = $valArr = [];
        foreach ($array as $key => $value) {
            $valArr[$key] = $value[$keys];
        }
        ($sort === 'asc') ? asort($valArr) : arsort($valArr);
        reset($valArr);
        foreach ($valArr as $key => $value) {
            $newArr[$key] = $array[$key];
        }
        return array_merge($newArr);
    }
}
